// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"log"
	"fmt"
	"crypto/md5"
	"bytes"
)

type Hub struct {
	// Registered clients.
	clients map[string]*Client

	// Inbound messages from the clients.
	broadcast chan []byte

	// say p to p
	say chan *MsgStruct

	// Register requests from the clients.
	register chan *Client

	// Unregister requests from clients.
	unregister chan *Client
}

func newHub() *Hub {
	return &Hub{
		broadcast:  make(chan []byte),
		say:  		make(chan *MsgStruct),
		register:   make(chan *Client),
		unregister: make(chan *Client),
		clients:    make(map[string]*Client),
	}
}


func (h *Hub) run() {
	for {
		select {
		case client := <-h.register:			
			data := []byte(fmt.Sprintf("%x",client))
    		s := fmt.Sprintf("%x", md5.Sum(data))
    		log.Printf("%s",s)
    		h.clients[s] = client
			client.send <- []byte("{\"type\":\"login\",\"msg\":\""+s+"_"+client.nickname+"\"}")
			client.send <- newline
			log.Printf("len(clients) %d",len(h.clients))
			var str string = ""
			for key ,client := range h.clients {
				str += fmt.Sprintf(",%s_%s",key,client.nickname)
			}
			message := []byte("{\"type\":\"list\",\"msg\":\""+str+"\"}")
			for key,client := range h.clients {
				select {
				case client.send <- message:
				default:
					close(client.send)
					delete(h.clients, key)
				}
			}
		case client := <-h.unregister:	
			data := []byte(fmt.Sprintf("%x",client))
    		s := fmt.Sprintf("%x", md5.Sum(data))				
			if _, ok := h.clients[s]; ok {
				delete(h.clients, s)
				close(client.send)
			}
			var str string = ""
			for key := range h.clients {
				str += fmt.Sprintf(",%s_%s",key,client.nickname)
			}
			message := []byte("{\"type\":\"list\",\"msg\":\""+str+"\"}")
			for key,client := range h.clients {
				select {
				case client.send <- message:
				default:
					close(client.send)
					delete(h.clients, key)
				}
			}
		case message := <-h.broadcast:
			for key,client := range h.clients {
				select {
				case client.send <- message:
				default:
					close(client.send)
					delete(h.clients, key)
				}
			}
		case msgdata  :=  <-h.say:
			log.Printf("msgdata.Msg %v",msgdata)
			message_fmt := fmt.Sprintf("{\"from\":\"%s\",\"msg\":\"%s\",\"type\":\"say\",\"to\":\"%s\"}",msgdata.From,msgdata.Msg,msgdata.To)
			message := []byte(message_fmt)
			message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1))
			if client, ok := h.clients[msgdata.From]; ok {
				log.Printf("find msgdata.From %v",msgdata.From)
				select {
				case client.send <- message:
				default:
					close(client.send)
					delete(h.clients, msgdata.From)
				}
			}
			if client, ok := h.clients[msgdata.To]; ok {
				log.Printf("find msgdata.To %v",msgdata.To)
				select {
				case client.send <- message:
				default:
					close(client.send)
					delete(h.clients, msgdata.To)
				}
			}	
		}
	}
}
